Crypto text
Here we will create a component to make the following effect possible on a slide
It consists of two parts
- WLX template
- small Javascript function to efficiently update the text
Handling text updates
One could use TextView or something similar, that automatically binds to Wolfram Language. However, if we have a lot of text or big paragraph it might break the line breaks and in general is a bit heavy then a single span
or div
in HTML tree.
.js
//just to reduce getElementById requests
const hashTable = {};
core.UpdateTextField = async (args, env) => {
const uid = await interpretate(args[1], env);
const data = await interpretate(args[0], env);
if (uid in hashTable) {
hashTable[uid].innerText = data;
} else {
hashTable[uid] = document.getElementById(uid);
hashTable[uid].innerText = data;
}
}
here we defined a function, that changes the text-content of a given HTML element found by a given ID
UpdateTextField[text_String, Id_String]
One can test it using HTML or WLX cells
.html
<span id="someId">Text</span>
UpdateTextField[RandomWord[], "someId"] // FrontSubmit
Crypto effect
The idea is to use Boltzmann weighted sampling function and pick up a letters from English alphabet. The original letter presented in the string will be "energetically" more favourable than the rest letters from the alphabet. The energy difference can be tuned by the statistical temperature T
CT`prop[T_] := Join[{Exp[(*FB[*)((1)(*,*)/(*,*)(2 T))(*]FB*)]}, (Exp[(*FB[*)((-1)(*,*)/(*,*)(2 T))(*]FB*)])&/@Range[26]]
and we need to match the uppercases and lowercases
CT`variants[c_] := If[LowerCaseQ[c], Join[{c}, Alphabet[]], Join[{c}, ToUpperCase/@Alphabet[]]]
now let us test
RandomChoice[CT`prop[0.2] -> CT`variants[#]] &/@ StringSplit["Hello World", ""] // StringRiffle
"H w l l o F o r l d"
Component approach
Now we can construct a sort of a wrapper function, that we can use at any text string
.wlx
CryptoText[TextX_String, OptionsPattern[]] := With[{
UId = CreateUUID[], cell = ResultCell[], win = CurrentWindow[],
slide = EventClone[OptionValue["Slide"]], onStartEvent = OptionValue["OnStart"]
},
Module[{
task,
crypted,
original,
temperature = 1.0,
mainTask, easeTask,
finished = False
},
original = StringSplit[TextX, ""];
crypted = original;
EventHandler[slide, {
"Slide" -> Function[Null,
(* show first time -> start *)
mainTask = SetInterval[
(crypted[[#]] = If[original[[#]] =!= " ", RandomChoice[CT`prop[temperature] -> CT`variants[original[[#]]]], original[[#]]]) &/@ RandomSample[Range[Length[original]]];
FrontSubmit[UpdateTextField[StringRiffle[crypted, ""], UId], "Window"->win];
, 100];
],
onStartEvent -> Function[Null,
(* slowly morph into the original text *)
With[{easeTask = SetInterval[temperature = temperature + 0.1(0.05 - temperature), 200]},
SetTimeout[
TaskRemove[easeTask];
TaskRemove[mainTask];
, 6000];
];
EventRemove[slide];
finished = True;
]
}];
EventHandler[cell, {"Destroy"->Function[Null,
(* if a cell was removed *)
Print["Removed"];
If[finished, Return[]];
TaskRemove[mainTask];
EventRemove[slide];
]}];
<span style="font-family:monospace" id="{UId}"><TextX/></span>
]
]
Options[CryptoText] = {"OnStart"->"", "Slide"->""};
The final function looks like this
CryptoText[text_String, "Slide"->slideEvent_String, "OnStart"->onStart_String] _String
- It returns a DOM element
span
with a unique Id. - It assigns an event listener to
slideEvent
, which is typically generated by SlideEventListener and check if a slide was revealed. - If the last thing is true it starts to regenerate text-string and update the DOM element using an Id generated previously.
- Once
onStart
pattern was captured (can be a fragment event - see animations), it reduces the statistical temperature to the minimum (easeTask
) and then stops the animation after some time
We can see it in action on the slide here
.slide
Just an empty slide to trigger an event on the next one
---
# <CryptoText OnStart={"fragment-1"} Slide={"slide-1"}>Heading</CryptoText>
This is a body of the slide
<CryptoText OnStart={"fragment-1"} Slide={"slide-1"}>Housework could be everyone’s work, not just “women’s work”. Why do women enable men to act oblivious to cleaning, grocery shopping, pet feeding, etc? Somehow when men live alone they figure out how to do all of those things all on their own. My friend’s husband claimed he didn’t know that sheets should be washed more than once a season. He said he didn’t know one had to clean toilets. He assumed that since you flush toilets they clean themselves. She tried to get him to help but he did an awful job so she let him off the hook.</CryptoText>
<br/>
<CryptoText OnStart={"fragment-1"} Slide={"slide-1"}>Wouldn’t it be better if she spent the time and energy to get him to do it right instead of letting him claim he is “just bad at it”. My sons were raised to clean toilets and change their own sheets. Hopefully, in their future homes, the housework will be equally divided.</CryptoText>
Stop <!-- .element: class="fragment" data-fragment-index="1" -->
<SlideEventListener Id={"slide-1"}/>
This effect will not work if a cell output is projected to another window, since Javascript cells are local and belongs to the original Notebook's window.
Press f
on a slide to make it fullscreen